home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / scsh-0.4 / scsh-0 / scsh-0.4.2 / scsh / select1.c < prev    next >
C/C++ Source or Header  |  1995-10-26  |  7KB  |  262 lines

  1. /* C support for scsh select call.
  2. ** Copyright (c) 1995 by Olin Shivers.
  3. */
  4.  
  5. #include "sysdep.h"
  6.  
  7. #include <sys/types.h>
  8. #if defined(HAVE_SYS_SELECT_H)
  9. #  include <sys/select.h>
  10. #endif
  11. #include <sys/time.h>
  12.  
  13. #include <errno.h>
  14. #include <stdio.h>
  15.  
  16. #include "cstuff.h"
  17. #include "fdports.h"    /* Accessors for Scheme I/O port internals. */
  18. #include "fdports1.h"    /* Import fdes2fstar(). */
  19. #include "machine/stdio_dep.h"    /* Import stdio buf-peeking ops. */
  20.  
  21. /* Make sure our exports match up w/the implementation: */
  22. #include "select1.h"
  23.  
  24. /* the traditional sleazy max non-function. */
  25. #define max(a,b) (((a) > (b)) ? (a) : (b))
  26.  
  27. extern int errno;
  28. extern FILE *fdes2fstar(int fd);
  29.  
  30. static void or2_fdset(fd_set *x, fd_set *y, int max_elt);
  31. static int copyback_fdvec(scheme_value portvec, fd_set *fdset);
  32.  
  33. /* RVEC, WVEC, and EVEC are Scheme vectors of integer file descriptors,
  34. ** I/O ports, and #f's. NSECS is an integer timeout value, or #f for
  35. ** infinite wait. Do the select() call, returning result fd_sets in the
  36. ** passed pointers. Return 0 for OK, otherwise error is in errno.
  37. */
  38.  
  39. int do_select(scheme_value rvec, scheme_value wvec,
  40.           scheme_value evec, scheme_value nsecs,
  41.           fd_set *rset_ans, fd_set *wset_ans, fd_set *eset_ans)
  42. {
  43.     struct timeval timeout, *tptr;
  44.     fd_set rset_bufrdy, wset_bufrdy, eset_bufrdy;    /* Buffered port hits. */
  45.     int rbuf_rdy=0, wbuf_rdy=0, bufrdy;    /* Set if we find buffered I/O hits. */
  46.     int max_fd = -1;            /* Max fdes in the sets. */
  47.     int nelts, i;
  48.     int nfound;
  49.  
  50.     FD_ZERO(rset_ans);        FD_ZERO(wset_ans);    FD_ZERO(eset_ans);
  51.     FD_ZERO(&rset_bufrdy);    FD_ZERO(&wset_bufrdy);    FD_ZERO(&eset_bufrdy);
  52.  
  53.     /* Scan the readvec elts. */
  54.     nelts = VECTOR_LENGTH(rvec);
  55.     for(i=nelts; --i >= 0; ) {
  56.     scheme_value elt = VECTOR_REF(rvec,i);
  57.     int fd;
  58.  
  59.     if( FIXNUMP(elt) ) {                /* It's an integer fdes. */
  60.         fd = EXTRACT_FIXNUM(elt);
  61.         FD_SET(fd, rset_ans);
  62.         }
  63.  
  64.     else if( elt != SCHFALSE ) {            /* It better be a port. */
  65.         FILE *f;
  66.         scheme_value data = *Port_PortData(elt);
  67.         fd = EXTRACT_FIXNUM(*PortData_Fd(data));
  68.         f = fdes2fstar(fd);
  69.         if( !f ) return -1;
  70.         else if( *PortData_Peek(data) != SCHFALSE /* Port has a peekchar */
  71.              || !ibuf_empty(f) ) {          /* Stdio buf has chars. */
  72.         FD_SET(fd, &rset_bufrdy);
  73.         rbuf_rdy = 1; /* Hit. */
  74.         }
  75.         else FD_SET(fd, rset_ans);          /* No buffered data. */
  76.         }
  77.  
  78.     max_fd = max(max_fd, fd);
  79.     }
  80.  
  81.     /* Scan the writevec elts. */
  82.     nelts = VECTOR_LENGTH(wvec);
  83.     for(i=nelts; --i >= 0; ) {
  84.     scheme_value elt = VECTOR_REF(wvec,i);
  85.     int fd;
  86.  
  87.     if( FIXNUMP(elt) ) {                /* It's an integer fdes. */
  88.         fd = EXTRACT_FIXNUM(elt);
  89.         FD_SET(fd, wset_ans);
  90.         }
  91.  
  92.     else if( elt != SCHFALSE ) {            /* It better be a port. */
  93.         FILE *f;
  94.         fd = EXTRACT_FIXNUM(*PortFd(elt));
  95.         f = fdes2fstar(fd);
  96.         if( !f ) return -1;
  97.         else if( !obuf_full(f) ) {          /* I/O buf has room. */
  98.         FD_SET(fd, &wset_bufrdy);        
  99.         wbuf_rdy = 1; /* Hit. */
  100.         }
  101.         else FD_SET(fd, wset_ans);          /* No room. */
  102.         }
  103.  
  104.     max_fd = max(max_fd, fd);
  105.     }
  106.  
  107.     /* Scan the exception-vec elts. */
  108.     nelts = VECTOR_LENGTH(evec);
  109.     for(i=nelts; --i >= 0; ) {
  110.     scheme_value elt = VECTOR_REF(evec,i);
  111.     int fd;
  112.  
  113.     if( FIXNUMP(elt) ) {            /* It's an integer fdes. */
  114.         fd = EXTRACT_FIXNUM(elt);
  115.         FD_SET(fd, rset_ans);
  116.         }
  117.  
  118.     else if( elt != SCHFALSE ) {            /* It better be a port. */
  119.         fd = EXTRACT_FIXNUM(*PortFd(elt));
  120.         FD_SET(fd, rset_ans);
  121.         }
  122.  
  123.     max_fd = max(max_fd, fd);
  124.     }
  125.  
  126.     bufrdy = rbuf_rdy || wbuf_rdy;
  127.     if( bufrdy ) {        /* Already have some hits on buffered ports, */
  128.     timeout.tv_sec = 0;    /* so we only poll the others.               */
  129.     timeout.tv_usec = 0;
  130.     tptr = &timeout;
  131.     }
  132.     else if ( FIXNUMP(nsecs) ) {
  133.     timeout.tv_sec = EXTRACT_FIXNUM(nsecs);    /* Wait n seconds. */
  134.     timeout.tv_usec = 0;
  135.     tptr = &timeout;
  136.     }
  137.     else tptr = NULL;                /* #f => Infinite wait. */
  138.  
  139.     nfound = select1(max_fd+1, rset_ans, wset_ans, eset_ans, tptr); /* Do it.*/
  140.  
  141.     /* EINTR is not an error return if we have hits on buffered ports
  142.     ** to report.
  143.     */
  144.     if( nfound < 0 )
  145.     if ( errno != EINTR || !bufrdy ) return -1;
  146.     else {    /* EINTR, but we have hits on buffered ports to report.  */
  147.         FD_ZERO(rset_ans);        /* This should never happen --   */
  148.         FD_ZERO(wset_ans);        /* EINTR on a zero-sec select()  */
  149.         FD_ZERO(eset_ans);        /* -- but I'm paranoid.          */
  150.         }
  151.  
  152.     /* OR together the buffered-io ready sets and the fd ready sets. */
  153.     if( rbuf_rdy ) or2_fdset(rset_ans, &rset_bufrdy, max_fd);
  154.     if( wbuf_rdy ) or2_fdset(wset_ans, &wset_bufrdy, max_fd);
  155.  
  156.     return 0;
  157.     }
  158.  
  159.  
  160.  
  161. /* x = x or y */
  162. static void or2_fdset(fd_set *x, fd_set *y, int max_elt)
  163. {
  164.     int i;
  165.     for(i=max_elt+1; --i >= 0;)
  166.     if( FD_ISSET(i,y) ) FD_SET(i,x);
  167.     }
  168.  
  169.  
  170.  
  171. /* PORTVEC is a vector of integer file descriptors and Scheme ports.
  172. ** Scan over the vector, and copy any elt whose file descriptor is in FDSET
  173. ** to the front of the vector. Return the number of elts thus copied.
  174. */
  175. static int copyback_fdvec(scheme_value portvec, fd_set *fdset)
  176. {
  177.     int vlen = VECTOR_LENGTH(portvec);
  178.     int i, j=0;
  179.     for( i = -1; ++i < vlen; ) {
  180.     scheme_value elt = VECTOR_REF(portvec, i);
  181.     int fd = EXTRACT_FIXNUM((FIXNUMP(elt)) ? elt : *PortFd(elt));
  182.     if( FD_ISSET(fd,fdset) ) {
  183.         FD_CLR(fd,fdset);    /* In case luser put elt in multiple times. */
  184.         VECTOR_REF(portvec, j) = elt;
  185.         j++;
  186.         }
  187.     }
  188.     return j;
  189.     }
  190.  
  191.  
  192. /* Overwrite every inactive element in the vector with #f;
  193. ** Return count of active elements.
  194. */
  195.  
  196. static int clobber_inactives(scheme_value portvec, fd_set *fdset)
  197. {
  198.     int count = 0;
  199.     int i = VECTOR_LENGTH(portvec);
  200.  
  201.     while( --i >= 0 ) {
  202.     scheme_value elt = VECTOR_REF(portvec, i);
  203.     if( elt != SCHFALSE ) {
  204.         int fd = EXTRACT_FIXNUM((FIXNUMP(elt)) ? elt : *PortFd(elt));
  205.         if( FD_ISSET(fd,fdset) ) {
  206.         FD_CLR(fd,fdset); /* In case luser put elt in multiple times. */
  207.         ++count;
  208.         }
  209.         else VECTOR_REF(portvec, i) = SCHFALSE; /* Clobber. */
  210.         }
  211.     }
  212.     return count;
  213.     }
  214.  
  215.  
  216. /* These two functions are the entry points to this file.
  217. *********************************************************
  218. */
  219.  
  220. /* Copy active elts back to the front of their vector;
  221. ** Return error indicator & number of hits for each vector.
  222. */
  223.  
  224. scheme_value select_copyback(scheme_value rvec, scheme_value wvec,
  225.                  scheme_value evec, scheme_value nsecs,
  226.                  int *r_numrdy, int *w_numrdy, int *e_numrdy)
  227. {
  228.     fd_set rset, wset, eset;
  229.  
  230.     if( do_select(rvec, wvec, evec, nsecs, &rset, &wset, &eset) ) {
  231.     *r_numrdy = *w_numrdy = *e_numrdy = 0;
  232.     return ENTER_FIXNUM(errno);
  233.     }
  234.     
  235.     *r_numrdy = copyback_fdvec(rvec, &rset);
  236.     *w_numrdy = copyback_fdvec(wvec, &wset);
  237.     *e_numrdy = copyback_fdvec(evec, &eset);
  238.     return SCHFALSE;
  239.     }
  240.  
  241.  
  242. /* Overwrite non-active elements in the vectors with #f;
  243. ** return error indicator & number of hits for each vector.
  244. */
  245.  
  246. scheme_value select_filter(scheme_value rvec, scheme_value wvec,
  247.                scheme_value evec, scheme_value nsecs,
  248.                int *r_numrdy, int *w_numrdy, int *e_numrdy)
  249. {
  250.     fd_set rset, wset, eset;
  251.  
  252.     if( do_select(rvec, wvec, evec, nsecs, &rset, &wset, &eset) ) {
  253.     *r_numrdy = *w_numrdy = *e_numrdy = 0;
  254.     return ENTER_FIXNUM(errno);
  255.     }
  256.     
  257.     *r_numrdy = clobber_inactives(rvec, &rset);
  258.     *w_numrdy = clobber_inactives(wvec, &wset);
  259.     *e_numrdy = clobber_inactives(evec, &eset);
  260.     return SCHFALSE;
  261.     }
  262.